<?php

namespace app\modules\backend\controllers;

use app\models\cacheModel\AdminRoleModel as AdminRoleCacheModel;
use app\models\cacheModel\SettingModel;
use app\models\tableModel\AdminRoleModel as AdminRoleDBModel;
use app\models\tableModel\AdminUserModel;
use app\models\tableModel\FileUploadRecordModel;
use app\modules\backend\model\LoginForm;
use app\service\RequestService;
use app\service\tool\ConvertService;
use app\service\tool\FileService;
use app\service\tool\GenerateService;
use app\service\tool\UtilsService;
use app\service\UploadFileService;
use app\service\UpYunService;
use yii\console\Exception as consoleException;
use yii\filters\VerbFilter;

/**
 * 公共
 */
class IndexController extends BaseController
{

    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {

        return [
            'verbs'  => [ // 请求方式
                'class'   => VerbFilter::className(),
                'actions' => [
                    ### 页面
                    'index-page'        => ['GET'],
                    'login-page'        => ['GET'],
                    'register-page'     => ['GET'],
                    'work-bench-page'   => ['GET'],
                    ### 接口
                    'login-detail'      => ['GET'],
                    'login'             => ['POST'],
                    'logout'            => ['POST'],
                    'get-ue-config'     => ['GET'],
                    'upload'     => ['POST'],
                    'get-keywords'      => ['POST'],
                    'upload-remote-img' => ['POST']
                ],
            ]
        ];
    }


    /**
     * 首页页面
     * @return mixed
     */
    public function actionIndexPage()
    {

        // 首页得走单独的布局
        $this->layout = '@app/views/layouts/backendMain';

        // ******************** 1、用户基本信息 ********************
        // 用户基本信息
        /* @var $userInfo AdminUserModel */
        $userInfo = \Yii::$app->admin->identity;
        // 默认头像
        if (empty($userInfo->avatar)) $userInfo->avatar = '/images/backend/default-thumb-boy.png';
        // 头像
        // $userInfo->avatar = UtilsService::addImgDomain($userInfo->avatar);
        // 判断账号中所属角色
        if (empty($userInfo['role_id'])) {
            return $this->showError('您的账号角色未分配，请联系管理员。', 403);
        }

        // ******************** 2、用户角色信息 ********************
        // 角色缓存模块
        $cacheRoleModel = AdminRoleCacheModel::loadModelDB($userInfo['role_id']);
        // 空的从数据库获取
        if (!$cacheRoleModel) {
            return $this->showError('您的账号角色未分配，请联系管理员，感谢您的配合。', 403);
        } else if ($cacheRoleModel['status'] != AdminRoleDBModel::getStatusOpen()) {
            return $this->showError('您的账号角色已被禁用，请联系管理员。', 403);
        }

        // 需要更新下缓存|PS.更新失败了，暂时不做提示了。首页用户使用才是王道
        if ($cacheRoleModel->getAttribute('needSave')) $cacheRoleModel->save();

        // 菜单
        $menus = $cacheRoleModel->getMenu();
        $menus = !is_array($menus) ? $menus : json_encode($menus, JSON_UNESCAPED_UNICODE);

        return $this->render('index', [
            'userInfo' => $userInfo,
            'menu'     => $menus,               // 菜单
        ]);
    }

    /**
     * 工作台
     * @return mixed
     */
    public function actionWorkBenchPage()
    {

        return $this->render('work-bench', []);
    }

    /**
     * 用户注册页面
     * @return mixed
     */
    public function actionRegisterPage()
    {

        // 注册和登录得走单独的布局
        $this->layout = '@app/views/layouts/backendLogin';
        return $this->render('register');
    }

    /**
     * 用户登录页面
     * @return mixed
     */
    public function actionLoginPage()
    {

        // 注册和登录得走单独的布局
        $this->layout = '@app/views/layouts/backendLogin';
        return $this->render('login');
    }


    /**
     * 登录
     */
    public function actionLogin()
    {

        // if (!\Yii::$app->admin->isGuest) return $this->jsonSuccess('成功');

        // 登录所需数据
        $data = [
            'LoginForm' => [
                'username'   => $this->post('username'),
                'password'   => $this->post('password'),
                'rememberMe' => $this->post('rememberMe')
            ]
        ];

        // 实例化登录类
        $model = new LoginForm();
        // 执行登录
        if (!$model->load($data) || !$model->login()) {

            $err = UtilsService::getModelError($model->errors);
            return $this->jsonFail($err['msg'], 400, [
                'error_hint' => $err
            ]);
        }

        // 提示
        return $this->jsonSuccess('成功');
    }

    /**
     * 退出登录
     */
    public function actionLogout()
    {

        \Yii::$app->admin->logout();

        $userInfo = \Yii::$app->admin->identity;
        if ($userInfo) {
            return $this->jsonFail('退出登录失败', 400);
        }

        return $this->jsonSuccess('成功');
    }

    /**
     * 获取登录账号信息
     */
    public function actionLoginDetail()
    {

        // 只能获取已登录自己的详情
        $id = \Yii::$app->admin->id;
        if (empty($id)) {

            return $this->jsonFail('请先登录', 401, [
                'error_detail' => '请先登录',
                'error_code'   => 401
            ]);
        }

        $detail = AdminUserModel::loadModel($id);

        // 看获取的data是否为空
        if (empty($detail)) {

            // 强制退出下
            $this->actionLogout();
            return $this->jsonFail('会话已过期，请重新登录', 401, [
                'error_detail' => '用户不存在',
                'error_code'   => 404
            ]);
        }

        // 账号是否禁用
        if ($detail['status'] == AdminUserModel::getStatDisabled()) {

            return $this->jsonFail('您的账号已经禁止使用，请联系管理员', 400, [
                'error_detail' => '账号已被封禁',
                'error_code'   => 404
            ]);
        }

        $detail = $detail->getAttributes([
            'id',
            'user_name',
            'nick_name',
            'status',
            'avatar',
            'role_id'
        ]);

        return $this->jsonSuccess('成功', [
            'userInfo' => $detail
        ]);
    }

    /**
     * 上传图片
     */
    public function actionUpload()
    {

        $errorImgPath = '/images/images-error.png';
        ### 1、场景
        // 获取场景
        $scenario = $this->request('scenario');
        // 场景值键
        $scenarioKey = FileUploadRecordModel::getScenarioKey($scenario, true);
        if (empty($scenarioKey)) return $this->jsonFail('场景不合法', 400, [
            'error_hint' => '请传输合法场景'
        ]);


        ### 2、渲染路径
        // 合并为字符串 组成为：goods/detail 格式
        $scenarioDir = implode('/', $scenarioKey);
        // 合并为字符串 组成为：goods-detail 格式
        $scenarioStr = implode('-', $scenarioKey);


        ### 3、将图片保存至本地
        // 年月日
        $fileTime = date("Y-m-d", time());
        // 最终保存的目录
        $endPath   = \Yii::getAlias('@uploadPath') . '/upload/' . $scenarioDir . '/';
        $fileModel = UploadFileService::loadModel('files', [
            'fileType'       => FileUploadRecordModel::getScenarioType($scenario),
            'isRandFileName' => true, // 重命名
            'filePath'       => $endPath . $fileTime,
            'filePrefix'     => $scenarioStr
        ]);

        // 保存文件
        if (!$fileModel->upload()) {
            $error = UtilsService::getModelError($fileModel->getErrors());
            return $this->jsonFail('上传失败', 400, [
                'error_hint' => $error['msg']
            ]);
        }

        // 本地上传信息 - 过滤路径
        $localInfo = $fileModel->getUploadInfo();
        // 单文件上传 塑造为数组
        if (!is_array(current($localInfo))) $localInfo = [$localInfo];


        ### 4、图片上传到第三方
        $upService = UpYunService::loadModel([
            'basePath' => implode('/', array_filter([
                SettingModel::getSetting('ossSavePath'), $scenarioDir
            ]))
        ]);

        $pathList   = [];
        $recordFile = []; // 写到文件上传记录表的文件
        $times      = time();
        $hasErrors  = [];
        $yunStorage = FileUploadRecordModel::isYunStorage(); // 是否开启第三方远程图
        foreach ($localInfo as $k => $v) {

            ### 未开启远程存储
            if (!$yunStorage) {
                $pathInfo = pathinfo($v['path']);

                // 图片预览叠加的是 成功的远程图
                $pathList[] = [
                    'state'         => 'SUCCESS',
                    'size'          => $v['size'],
                    'title'         => $pathInfo['filename'],
                    'type'          => '.' . $pathInfo['extension'],
                    'path'          => $v['path'],
                    'relative_path' => $v['path'],
                ];
                // 文件上传记录表数据
                $recordFile[] = [
                    'id'               => GenerateService::newMongoId(),
                    'name'             => $v['name'],
                    'path'             => $v['path'],
                    'third_return_url' => '',
                    'status'           => FileUploadRecordModel::getStatusNormal(),
                    'scenario'         => $scenario,
                    'file_type'        => $upService->getResult('mimetype'),
                    'uid'              => \Yii::$app->admin->id,
                    'add_time'         => $times,
                    'update_time'      => $times,
                    'is_admin'         => FileUploadRecordModel::getIsAdminYes()
                ];
            } ### 第三方存储上传出错
            else if (!$upService->uploadImage($v['full'])) {
                $error = UtilsService::getModelError($upService->errors);
                // 图片预览叠加的是错误图
                $pathInfo   = pathinfo($errorImgPath);
                $pathList[] = [
                    'state'      => 'ERROR',
                    'size'       => '0',
                    'title'      => $pathInfo['filename'],
                    'type'       => '.' . $pathInfo['extension'],
                    'path'       => $errorImgPath,
                    'error_hint' => $error['msg']
                ];
                $hasErrors  = true;
            } ### 第三方存储上传成功
            else {
                $pathInfo = pathinfo($upService->getResult('url'));

                // 图片预览叠加的是 成功的远程图
                $pathList[] = [
                    'state'         => 'SUCCESS',
                    'size'          => $v['size'],
                    'title'         => $pathInfo['filename'],
                    'type'          => '.' . $pathInfo['extension'],
                    'path'          => $upService->getResult('url'),
                    'relative_path' => FileService::delImgDomain($upService->getResult('url')),
                ];
                // 文件上传记录表数据
                $recordFile[] = [
                    'id'               => GenerateService::newMongoId(),
                    'name'             => $v['name'],
                    'path'             => $v['path'],
                    'third_return_url' => FileService::delImgDomain(
                        $upService->getResult('url')
                    ),
                    'status'           => FileUploadRecordModel::getStatusNormal(),
                    'scenario'         => $scenario,
                    'file_type'        => $upService->getResult('mimetype'),
                    'uid'              => \Yii::$app->admin->id,
                    'add_time'         => $times,
                    'update_time'      => $times,
                    'is_admin'         => FileUploadRecordModel::getIsAdminYes()
                ];
            }

            // 远程图删除原图下本地文件
            if ($yunStorage) unlink($v['full']);
        }

        // 写入上传记录
        // if (!empty($recordFile)) FileUploadRecordModel::createData($recordFile);

        return $this->jsonSuccess('上传成功',
            count($pathList) == 1 ? $pathList[0] : $pathList);
    }

    /**
     * 拉远程图片
     * @return mixed
     */
    public function actionUploadRemoteImg()
    {

        $errorImgPath = '/images/images-error.png';

        ### 1、抓取的图片列表
        $images = $this->post('source');
        if (count($images) > 10) {
            return $this->jsonFail('文本中图片数量不得大于10个, 您可以分批复制一次10个',
                400,
                [
                    'errorImgPath' => $errorImgPath,
                    'error_hint'   => '请传输场景'
                ]);
        }
        // 非数组改为数组
        $images = !is_array($images) ? explode(',', $images) : $images;

        ### 2、抓取的场景
        $sceListKey = array_keys(FileUploadRecordModel::getTypeList());
        // 获取场景
        $scenario = $this->post('scenario');
        $scenario = empty($scenario) ? $this->get('scenario') : $scenario;
        // 场景不合法
        if (empty($scenario) || !in_array($scenario, $sceListKey)) {
            return $this->jsonFail('请传输场景', 400, [
                'errorImgPath' => $errorImgPath,
                'error_hint'   => '请传输场景'
            ]);
        }
        // 将 _ 替换为 -
        $scenario = str_replace('_', '-', $scenario);
        // 根据大写字母分割为数组
        $scenarioFormat = UtilsService::splitUpperCase($scenario);
        // 合并为字符串 组成为：goods/detail 格式
        $scenarioDir = implode('/', $scenarioFormat);
        // 合并为字符串 组成为：goods-detail 格式
        $scenarioStr = implode('-', $scenarioFormat);


        ### 3、图片列表循环
        $dates        = date('Y-m-d', time());
        $upYunService = UpYunService::loadModel([
            'basePath' => '/www/' . $scenarioDir
        ]);
        $pathList     = [];
        $recordFile   = []; // 写到文件上传记录表的文件
        $time         = time();
        $hasErrors    = [];
        $yunStorage   = FileUploadRecordModel::isYunStorage(); // 是否开启第三方远程图
        $rmScheme     = false; // 是否需要移除协议头
        foreach ($images as $k => $v) {

            // 先做检测 - 如果是已经非远程图略过
            if (FileService::isLocalImage($v)) continue;

            ### 4、图片单个下载到本地
            // 首先检测连接前两个字符是否为 // 要加个 http
            $rmScheme = false; // 默认 无需移除协议头
            if (UtilsService::cutString($v, 0, 2, '') == '//') {
                $v        = 'http:' . $v;
                $rmScheme = true;
            }
            // 获取当前文件扩展名
            // example：/upload/download/2020-11-09/5fa8ae34f6cdbc01854c4d27.jpg
            $savePath = '/upload/download/' . $dates . '/{RANDOM}' . '{EXT}';
            ### 下载地址格式化
            // 日期替换
            $savePath = GenerateService::generatePath($savePath);
            // 需要增加项目内[uploadPath]别名
            $savePath = \Yii::getAlias('@uploadPath') . $savePath;

            $result = UtilsService::downImage($v, $savePath);

            ### 5、图片单个上传到云
            // 如果无需执行上传
            if (!$yunStorage && $result) {

                // 图片预览叠加的是 成功的远程图
                $pathList[] = [
                    'state'  => 'SUCCESS',
                    'size'   => filesize($result['absolute_path']),
                    'title'  => $result['name'],
                    'type'   => $result['ext'],
                    'path'   => $result['relative_path'],
                    'source' => $rmScheme ? str_replace('http:', '', $v) : $v,
                ];
                // 文件上传记录表数据
                $type         = FileUploadRecordModel::getTypeVal($scenario);
                $recordFile[] = [
                    'id'               => GenerateService::newMongoId(),
                    'name'             => $result['name'],
                    'path'             => $result['relative_path'],
                    'third_return_url' => null,
                    'status'           => FileUploadRecordModel::getStatusNormal(),
                    'type'             => $type,
                    'file_type'        => $result['ext'],
                    'uid'              => \Yii::$app->admin->id,
                    'add_time'         => $time,
                    'update_time'      => $time,
                    'is_admin'         => FileUploadRecordModel::getIsAdminYes()
                ];
                continue;
            } // 执行上传 失败
            else if (!$upYunService->uploadImage($result['path']) || $result) {
                $error = UtilsService::getModelError($upYunService->errors);
                // 图片预览叠加的是错误图
                $pathList[] = [
                    'state'      => 'ERROR',
                    'source'     => $v,
                    'size'       => $upYunService->getResult('file_size'),
                    'title'      => 'error.png',
                    'type'       => 'png',
                    'path'       => $errorImgPath,
                    'error_hint' => !$result ? '上传失败, 请查看日志' : $error['msg']
                ];
                $hasErrors  = true;
            } else {

                $pathInfo = pathinfo($upYunService->getResult('url'));
                // 图片预览叠加的是 成功的远程图
                $pathList[] = [
                    'state'  => 'SUCCESS',
                    'source' => $v,
                    'size'   => $upYunService->getResult('file_size'),
                    'title'  => $pathInfo['filename'] . "." . $pathInfo['extension'],
                    'type'   => $pathInfo['extension'],
                    'path'   => $upYunService->getResult('url'),
                ];
                // 文件上传记录表数据
                $type         = FileUploadRecordModel::getTypeVal($scenario);
                $recordFile[] = [
                    'id'               => GenerateService::newMongoId(),
                    'name'             => $result['name'],
                    'path'             => $result['relative_path'],
                    'third_return_url' => FileService::delImgDomain(
                        $upYunService->getResult('url')
                    ),
                    'status'           => FileUploadRecordModel::getStatusNormal(),
                    'type'             => $type,
                    'file_type'        => $upYunService->getResult('mimetype'),
                    'uid'              => \Yii::$app->admin->id,
                    'add_time'         => $time,
                    'update_time'      => $time,
                    'is_admin'         => FileUploadRecordModel::getIsAdminYes()
                ];
            }

            // 删除下本地文件
            unlink($result['absolute_path']);
        }

        ### 6、添加下上传记录
        FileUploadRecordModel::createData($recordFile);

        return $this->jsonSuccess('成功', $pathList);
    }

    /**
     * 获取文本关键词
     */
    public function actionGetKeywords()
    {

        // 内容获取
        $content = $this->request('content');
        if (empty($content)) {
            return $this->jsonFail('请传输内容', 400);
        }

        // 取出汉子、数字、字母
        preg_match_all("/[a-zA-Z0-9\x{4e00}-\x{9fa5}]/u", html_entity_decode($content), $content);
        $content = join("", $content[0]);
        $content = ConvertService::clearAllSpace($content);

        $count      = 1;
        $resultList = [];
        $size       = 500;
        while (true) {

            // 此次要循环获取的字符串
            $str = UtilsService::cutString($content,
                $size * ($count - 1), $size);

            // 字符长度小于 1
            if (!$str || strlen($str) < 1) {
                break;
            }

            $request = RequestService::loadModel([
                'url'    => 'http://api.pullword.com/get.php',
                'params' => [
                    'source' => $str,
                    'param1' => 0,
                    'param2' => 1,
                    'json'   => 1
                ],
                'method' => RequestService::getMethodGet()
            ]);
            $do      = $request->doRequest();
//            if (!$do) {
//                $error = UtilsService::getModelError($request->errors);
//                return $this->jsonFail('获取关键词失败', $error['msg']);
//            }

            $result = $request->getResult();
            // 结果存储
            $result = json_decode(empty($result) ? null : $result, true);
            // 最终结果合并
            $resultList = array_merge(empty($result) ? [] : $result, $resultList);
            // 次数 + 1
            $count = $count + 1;
            // 不能大于20次
            if ($count >= 20) {
                break;
            }
        }

        // [JSON]字符转数组
        $resultList = array_column($resultList, null, 'p');
        krsort($resultList);

        return $this->jsonSuccess('成功',
            array_unique(array_column($resultList, 't')));
    }
}
